package grpcx

import (
	"context"
	"fmt"
	etcdv3 "go.etcd.io/etcd/client/v3"
	"go.etcd.io/etcd/client/v3/naming/endpoints"
	"go.uber.org/zap"
	"google.golang.org/grpc"
	"jk-time/webook/pkg/netx"
	"log"
	"net"
	"strconv"
	"time"
)

type Server struct {
	*grpc.Server
	Port     int
	EtcdAddr string
	Name     string
	kaCancel func()
	manager  endpoints.Manager
	cli      *etcdv3.Client
	key      string
}

func (s *Server) Serve() error {
	addr := fmt.Sprintf(":%d", s.Port)
	conn, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	log.Printf("Listen port:%v\n", s.Port)
	err = s.register()
	if err != nil {
		return err
	}

	return s.Server.Serve(conn)
}
func (s *Server) register() error {
	cli, err := etcdv3.NewFromURL(s.EtcdAddr)
	if err != nil {
		return err
	}
	s.cli = cli
	manager, err := endpoints.NewManager(cli, "service/"+s.Name)
	if err != nil {
		return err
	}
	s.manager = manager
	addr := netx.GetOutboundIP() + ":" + strconv.Itoa(s.Port)

	s.key = "service/" + s.Name + "/" + addr

	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	var ttl int64 = 5
	leaseResp, err := s.cli.Grant(ctx, ttl)
	if err != nil {
		return err
	}

	//租约
	err = s.manager.AddEndpoint(ctx, s.key, endpoints.Endpoint{
		Addr: addr,
	}, etcdv3.WithLease(leaseResp.ID))
	if err != nil {
		return err
	}

	kaCtx, kaCancel := context.WithCancel(context.Background())
	s.kaCancel = kaCancel
	//开启自动续约
	ch, err := s.cli.KeepAlive(kaCtx, leaseResp.ID)
	go func() {
		for resp := range ch {
			zap.L().Debug(resp.String())
		}
	}()

	return err
}
func (s *Server) Close() error {
	if s.kaCancel != nil {
		s.kaCancel()
	}
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	err := s.manager.DeleteEndpoint(ctx, s.key)
	cancel()
	if err != nil {
		return err
	}
	s.Server.GracefulStop()
	return nil
}
